package com.ipan.kits.security;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import org.apache.commons.lang3.Validate;

import com.ipan.kits.base.ExceptionUtil;
import com.ipan.kits.base.MoreValidate;
import com.ipan.kits.text.EncodeUtil;

/**
 * MD5摘要计算
 *
 * @author iPan
 * @date 2019-05-20
 */
public class MD5 {

    /**
     * md5计算
     *
     * @param data 待计算的数据
     * @return md5计算结果
     */
    public static byte[] digest(final byte[] data) {
    	MoreValidate.notEmpty(data, "The data is null or empty.");
        return DigestUtil.getMd5Digest().digest(data);
    }

    /**
     * 将输入流的数据进行MD5计算
     *
     * @param data 待计算的数据
     * @return md5计算结果
     */
    public static byte[] digest(final InputStream data) {
        Validate.notNull(data, "The data is null.");
        try {
            return DigestUtil.digest(DigestUtil.getMd5Digest(), data);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 计算字符串的md5值，结果转为16进制的字符串返回,默认采用{@link StandardCharsets#UTF_8}编码
     *
     * @param data 待计算的数据
     * @return 16进制的字符串
     */
    public static String digestHex(final String data) {
        return digestHex(data, StandardCharsets.UTF_8);
    }

    /**
     * 计算字符串的md5值，结果转为16进制的字符串返回
     *
     * @param data    待计算的数据
     * @param charset 指定编码，为空时采用UTF8读取
     * @return 16进制的字符串
     */
    public static String digestHex(final String data, final Charset charset) {
    	Validate.notBlank(data, "The data is null or empty.");
        byte[] salt = data.getBytes(charset == null ? StandardCharsets.UTF_8 : charset);
        byte[] md5Data = digest(salt);
        return EncodeUtil.encodeHex(md5Data);
    }
    
    public static String digestHex(final byte[] data) {
    	MoreValidate.notEmpty(data, "The data is null or empty.");
    	byte[] md5Data = digest(data);
        return EncodeUtil.encodeHex(md5Data);
    }

    /**
     * 计算的流的md5值，结果转为16进制的字符串返回
     *
     * @param data 待计算的数据
     * @return 16进制的字符串
     */
    public static String digestHex(final InputStream data) {
        return EncodeUtil.encodeHex(digest(data));
    }
    
    /**
     * 计算文件md5
     *
     * @param file 文件
     * @return 16进制的字符串
     */
    public static String digestHex(final File file) {
    	FileInputStream fin = null;
    	String md5 = null;
    	try {
    		fin = new FileInputStream(file);
    		md5 = digestHex(fin);
    	} catch(Exception e) {
    		ExceptionUtil.wrapRuntime(e);
    	} finally {
    		if (fin != null) {
    			try {
					fin.close();
				} catch (IOException e) {
				}
    		}
    	}
    	return md5;
    }

    /**
     * 计算字符串(默认UTF8)的MD5值，将结果转为BASE64输出
     *
     * @param data 待计算的数据
     * @return BASE64的字符串
     */
    public static String digestBase64(final String data) {
        return digestBase64(data, StandardCharsets.UTF_8);
    }
    
    public static String digestBase64(final byte[] data) {
    	MoreValidate.notEmpty(data, "The data is null or empty.");
    	byte[] md5Data = digest(data);
        return EncodeUtil.encodeBase64(md5Data);
    }
    
    /**
     * 计算字符串的MD5值，将结果转为BASE64输出
     *
     * @param data    待计算的数据
     * @param charset 字符串编码
     * @return BASE64的字符串
     */
    public static String digestBase64(final String data, final Charset charset) {
    	Validate.notBlank(data, "The data is null or empty.");
        byte[] salt = data.getBytes(charset == null ? StandardCharsets.UTF_8 : charset);
        byte[] md5Data = digest(salt);
        return EncodeUtil.encodeBase64(md5Data);
    }
}
